package ru.averta.notes.service.impl;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.averta.notes.dao.UrlDao;
import ru.averta.notes.domain.Url;
import ru.averta.notes.other.UtilsCommon;
import ru.averta.notes.service.UrlService;
import ru.averta.notes.service.security.SecurityService;

import java.util.*;

/**
 * <code>CoolMarkServiceImpl</code>
 *
 * @author fedor.belov (fedor.belov@mail.ru)
 *         Date: 13.09.11 15:40
 */

@Service
@Transactional
public class UrlServiceImpl implements UrlService {

    @Autowired private UrlDao dao;
    @Autowired private SecurityService security;

    @Override public Collection<Long> findUrlsByCUser() {
        return dao.findUrlsByUser(security.getCurrentUser());
    }

    @Override
    public Url findOrCreateUrl(String url) {
        Url urlObject = dao.findUrlObjectByUrl(url);

        if (urlObject == null) {
            urlObject = new Url(url);
            dao.save(urlObject);
        }

        return urlObject;
    }

    @Override
    public Map<Set<String>, Set<Long>> combineUrlsByTags() {
        List<Object[]> source = dao.findUrlsAndTagsByUser(security.getCurrentUser());

        Map<Set<String>, Set<Long>> result = new HashMap<Set<String>, Set<Long>>();
        ArrayList<String> tags = null;
        Long urlId = null;

        for (Object[] row : source) {
            if (urlId == null) {
                urlId = (Long) row[0];
                tags = new ArrayList<String>(5);
            } else if (!(urlId.equals((Long) row[0]))) {
                //Если дальше следует другой url, то строим комбинации тегов для данного url
                loadCombinations(result, urlId, tags);

                urlId = (Long) row[0];
                tags = new ArrayList<String>(5);
            }

            tags.add((String) row[1]);
        }

        loadCombinations(result, urlId, tags);

        return result;
    }

    @Override
    public Collection<Long> getUrlsByTags(Set<String> tags) {
        //todo закешировать результат

        //Вариант реализации
        /*Map<Set<String>, Set<Long>> urlsByTags = combineUrlsByTags();
        return urlsByTags.get(tags);*/

        //Варинт реализации 2
        Map<String, Set<Long>> simpleUrlsByTags = getUrlsByTags();
        Collection<Long> result = null;
        for (String tag : tags) {
            Set<Long> urls = simpleUrlsByTags.get(tag);
            if (urls == null) {
                //нет ни одного сайта с тегом tag
                return new HashSet<Long>();
            } else if (result == null) {
                result = urls;
            } else {
                result = CollectionUtils.intersection(result, urls);
            }
        }

        return result;
    }

    private Map<String, Set<Long>> getUrlsByTags() {
        //todo закешировать результат

        Map<String, Set<Long>> result = new HashMap<String, Set<Long>>();
        List<Object[]> source = dao.findTagsAndUrlsByUser(security.getCurrentUser());

        String tag = null;
        HashSet<Long> urls = null;

        for (Object[] row : source) {
            if (tag == null) {
                tag = (String) row[0];
                urls = new HashSet<Long>();
            } else if (!tag.equals((String) row[0])) {
                result.put(tag, urls);

                tag = (String) row[0];
                urls = new HashSet<Long>();
            }

            urls.add((Long) row[1]);
        }

        result.put(tag, urls);

        return result;
    }

    private void loadCombinations(Map<Set<String>, Set<Long>> result, Long urlId, ArrayList<String> tags) {
        Collection<Set<String>> tagCombinations = UtilsCommon.getCombinations(tags);

        for (Set<String> tagCombination : tagCombinations) {
            Set<Long> urls = result.get(tagCombination);
            if (urls == null) {
                urls = new HashSet<Long>();
                urls.add(urlId);
                result.put(tagCombination, urls);
            } else {
                urls.add(urlId);
            }
        }
    }


}
